/**
 * @file perform.cpp
 * @author Xin Yuan
 *
 * Modified by Alejandro Cabrera:
 *  - Removed all magic numbers and replaced them with global, clear constants
 *  - Reduced size of data pointer
 *  - Removed legacy comments
 *  - Now size-agnostic
 *
 * This program produces no output. A memroy manager that can pass tests 1-5
 * is considered correct. This test only tests speed.
 */
#include <cstdlib>
#include <stdint.h>
#include <iostream>

#ifndef MYMEM
#define MyMemAlloc(x) malloc((x))
#define MyMemFree(x) free((x))
#else
#define MyMemAlloc(x) m.mymalloc((x))
#define MyMemFree(x) m.myfree((x))
#include "../include/mm.h"
static const uint32_t NODE_SIZE = sizeof(NodeType);
static const uint32_t NODE_CNT = 25000;
static const uint32_t NODE_MEMORY = NODE_CNT * NODE_SIZE;
static const uint32_t MEMORY_SIZE = NODE_MEMORY * 2;
MemoryManager m(MEMORY_SIZE, NODE_MEMORY);
#endif

static const uint32_t DATA_SIZE = 300000;
static const uint32_t ZEROED_ELEMENTS = 10000;
static const uint32_t INITIAL_RANGE_END = 1000;
static const uint32_t NUM_ALLOCS = 500;
static const uint32_t MAX_ALLOC_SIZE1 = 300*4 + 100;
static const uint32_t MAX_ALLOC_SIZE2 = 50*4 + 100;
static const uint32_t MAX_ITERS = 200000;

int main()
{
  void *data[DATA_SIZE];
  size_t last = 0;

  // clear a few data segments
  for (size_t i = 0; i < ZEROED_ELEMENTS; ++i){
    data[i] = 0;
  }

  // allocate a few random blocks of memory
  for (size_t i = 0; i < NUM_ALLOCS; ++i) {
    data[i] = MyMemAlloc(random() % MAX_ALLOC_SIZE1);
  }
  last = INITIAL_RANGE_END;

  // randomly allocate or free a block of memory in the range [0,last]
  for (size_t i = 0; i < MAX_ITERS; ++i) {

    // choose a random block to free
    if (random() % 2 == 0) {
      int ii = random() % last;

      // loop until a null word is found or until ii becomes negative
      while ((data[ii] == 0) && (ii >= 0)) {
	ii--;
      }
      // if ii is still greater than 0 and the data word is not null,
      // then we free the data element and set it to null
      if ((ii >= 0) && (data[ii] != 0)) {
	MyMemFree(data[ii]);
	data[ii] = 0;
      }
    }

    // choose an element of data and allocate a block of memory to it
    else {
      data[last++] = MyMemAlloc(random() % MAX_ALLOC_SIZE2);
    }
  }

  return 0;
}
